package node;

import lexer.LexType;
import parser.Parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class InitValNode extends ASTNode {
    public final String name = "<InitVal>";
    // InitVal → Exp | '{' [ Exp { ',' Exp } ] '}' | StringConst
    private List<ExpNode> expNodes = new ArrayList<>();
    private String stringConst;
    private ExpNode expNode;

    public InitValNode(List<ExpNode> expNodes) {
        this.expNodes = expNodes;
    }

    public InitValNode(String stringConst) {
        this.stringConst = stringConst;
    }

    public InitValNode(ExpNode expNode) {
        this.expNode = expNode;
    }

    @Override
    public void show() throws IOException {
        if (expNode != null) {
            expNode.show();
        } else if (stringConst != null) {
            Parser.parserWriter.write(LexType.STRCON + " " + stringConst + "\n");
        } else {
            Parser.parserWriter.write(LexType.LBRACE + " " + "{" + "\n");
            for (int i = 0; i < expNodes.size(); i++) {
                expNodes.get(i).show();
                if (i != expNodes.size() - 1) {
                    Parser.parserWriter.write(LexType.COMMA + " " + "," + "\n");
                }
            }
            Parser.parserWriter.write(LexType.RBRACE + " " + "}" + "\n");
        }
        Parser.parserWriter.write(name + "\n");
    }

    public String getStringConst() {
        return stringConst;
    }

    public ExpNode getExpNode() {
        return expNode;
    }

    public List<ExpNode> getExpNodes() {
        return expNodes;
    }

    public List<Integer> calculateArray() {
        List<Integer> res = new ArrayList<>();
        for (ExpNode expNode : expNodes) {
            res.add(expNode.calculate());
        }
        return res;
    }

    public int calculate() {
        if (expNode != null) {
            return expNode.calculate();
        } else {
            return expNodes.size();
        }
    }

    public String calculateCharArray() {
        StringBuilder sb = new StringBuilder();
        if (stringConst != null) {
            for (int i = 1; i < stringConst.length() - 1; i++) {
                char c = stringConst.charAt(i);
                if (c == '\\') {
                    char next = stringConst.charAt(++i);
                    switch (next) {
                        case 'a':
                            sb.append('\007');
                            break;
                        case 'v':
                            sb.append('\013');
                            break;
                        case '0':
                            sb.append('\0');
                            break;
                        case 'n':
                            sb.append('\n');
                            break;
                        case 't':
                            sb.append('\t');
                            break;
                        case 'f':
                            sb.append('\f');
                            break;
                        case 'r':
                            sb.append('\r');
                            break;
                        case 'b':
                            sb.append('\b');
                            break;
                        case '\"':
                            sb.append('\"');
                            break;
                        case '\\':
                            sb.append('\\');
                            break;
                        case '\'':
                            sb.append('\'');
                            break;
                        default:
                            sb.append(next);
                            break; // 非标准转义字符
                    }
                } else {
                    sb.append(c);
                }
            }
        } else if (expNodes.size() > 0) {
            for (ExpNode expNode : expNodes) {
                sb.append((char) expNode.calculate());
            }
        } else {
            // 说明是空数组
            sb.append("");
        }
        return sb.toString();
    }

    public boolean canCaclulate() {
        if (stringConst != null) {
            return true;
        }
        if (expNode.canCaclulate()) {
            return true;
        }
        for (ExpNode expNode : expNodes) {
            if (!expNode.canCaclulate()) {
                return false;
            }
        }
        return true;
    }

}
